package process

import (
	"dmsv/common"
	ss "dmsv/session"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"i-hea/utils/httplib"
	"os"
	"time"
)

var httpClient *httplib.HttpClient

type Notifyv2Args struct {
	Caller    string `json:"caller"`      //外显号码
	Number    string `json:"callee"`      //被叫号码
	companyId string `json:"appId"`       //企业Id
	PlayFile  string `json:"playFile"`    //放音文件
	GetKey    bool   `json:"gegKey"`      //按键支持,可选，默认不开启
	PlayTime  int    `json:"playTime"`    //播放次数
	CallBack  string `json:"callBackUri"` //接收回调的地址
}

type ArgsOfNotify struct {
	CallId   string
	Caller   string
	Callee   string
	PlayFile string
	Method   string
	DevId    string
	PlayTime int
	Wait     int //最长等待音
	Delay    int //延迟挂机时长
}

func fileIsExists(path string) bool {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if os.IsExist(err) {
			return true
		}
		return false
	}
	return true
}

func CallNotify(args ArgsOfNotify) error {

	recv := make(chan *ss.CallBackData, 10)
	uri := gCallBack + callbackNotify
	mediaFile := fmt.Sprintf("file_string://%s%s", gMediaDir, "verifycode_is.wav")

	playFile := ""
	callee := args.Callee
	if args.Method == NotifyVerify {
		uri = gCallBack + callbackVerify
		for _, v := range args.PlayFile {
			mediaFile += fmt.Sprintf("!%s%c.wav", gMediaDir, v)
		}
		playFile = mediaFile
		if gPrefixEnable {
			callee = gVerifyPrefix + args.Callee
		}
	} else {

		if gPrefixEnable {
			callee = gNotifyPrefix + args.Callee
		}

		playFile = fmt.Sprintf("%s%s", gNotifyDir, args.PlayFile)
		if false == fileIsExists(playFile) {
			logs.Error("[%v] callee :%v media file is not exist", args.CallId, args.Callee)
			return fmt.Errorf("media file is not exist")
		}
	}

	/*
		ok := ss.AddNewNotify(args.Caller, callee, args.CallId, gVosAddr, args.Wait, args.Delay, recv)
		if !ok {
			logs.Error("%v add to call task failed.", args.CallId)
			return fmt.Errorf("call is full")
		}
	*/
	logs.Debug("[%v]new notify: caller:%v callee:%v delay:%v", args.CallId, args.Caller, callee, args.Delay)
	go func() {

		callResult := CALL_RESULT_SUCCESS
		playCount := args.PlayTime
		playTimes := args.PlayTime
		if playTimes == 0 {
			playCount = 1
			playTimes = 1
		}

		arg := ss.DTMF_ARGS{
			EndKey:    "*#",
			MediaFile: playFile,
		}
	Loop:
		for {

			result := <-recv
			logs.Debug("[%v]receive result:%v，playtimes:%d  ",
				args.CallId, ss.ConvertCallStatusToString(result.Event), playCount)
			switch result.Event {
			case ss.CALL_EVENT_ANSWER:

				fileName := createRecordName(args.CallId, args.Caller, args.Callee)
				result.Ssion.StartRecord(fileName)

				result.Ssion.PlayAndGetKey(arg)

			case ss.CALL_EVENT_FAIL:
				//发起外呼失败
				sendErrResponseGet(uri, args.CallId, errSystem)
				break Loop

			case ss.CALL_EVENT_PLAY_OVER:
				playCount--

				if playCount > 0 {
					result.Ssion.PlayAndGetKey(arg)
				} else if playCount <= 0 {

					// 在播放的过程中用户挂机 ，fs也会发送playover事件,为确保播放完成事件的准确性,此处延时
					time.Sleep(100 * time.Millisecond)
					result.Ssion.HangUp(nil)
				}

			case ss.CALL_EVENT_HANGUP:
				hangUp := result.Data.(*ss.HangInfo)
				logs.Debug("[%v]hangup dir:%v,line:%v，duration:%v seconds",
					args.CallId, hangUp.Dir, result.Dir, hangUp.Duration)

				timeStamp := "00000"
				if !hangUp.AnswerTime.IsZero() {
					timeStamp = fmt.Sprintf("%d", hangUp.AnswerTime.Unix())
				}

				rs := errCode{}
				if hangUp.Duration > 0 &&
					(hangUp.Dir == ss.HANG_UP_SYSTEM || len(hangUp.SipCode) == 0) {
					rs = errPlayOver
				} else {

					//播放中挂机
					switch hangUp.Dir {
					case ss.HANG_UP_LINEERR:
						callResult = CALL_RESULT_FAIL
						rs = errCalleeUnreach
					case ss.HANG_UP_USER:
						rs = errCalleeHangup
					case ss.HANG_UP_SYSTEM:
						rs = errCalleeHangup
					case ss.HANG_UP_REFUSE:
						rs = errCalleeRefuse
					default:
						//未接听
						rs = errCalleeUnAnswer
					}
				}

				sendResultGet(uri, args.CallId, timeStamp, "", callResult, hangUp.Duration, rs)

				break Loop
			case ss.CALL_EVENT_DTMF:
				dtmf := result.Data.(ss.DtmfEvent)

				logs.Debug("[%v] receive dtmf:%v,end TimeOut:%v", result.CallId, dtmf.Dtmf, dtmf.TimeOut)
				sendDtmfGet(args.CallId, args.DevId, dtmf.Dtmf, callTypeNotify)

			default:
				logs.Error("[%v]wrong event:%v,drop", result.CallId, ss.ConvertCallStatusToString(result.Event))
			}
		}

		logs.Debug("[%v] call notify finished", args.CallId)
		ss.DesdroyTheCall(args.CallId)

	}()
	return nil
}

func CallNotifyv2(args Notifyv2Args) (string, error) {

	callId := createUUid()
	eventChan := make(chan *ss.CallBackData, 10)

	/*
		callee := args.Number
			router := callrouter.GetDefaultRouter()
			ok := ss.AddNewNotify(args.Caller, callee, callId, router, 60, 2, eventChan)
			if !ok {
				logs.Error("%v add to call task failed.", callId)
				return "", fmt.Errorf("call is full")
			}
	*/
	//logs.Debug("[%v]new notify: caller:%v callee:%v delay:%v", args.CallId, args.Caller, callee, args.Delay)
	go func() {
		rs := errCode{}
		playCount := args.PlayTime

	Loop:
		for {

			result := <-eventChan
			logs.Debug("[%v]receive result:%v，playtimes:%d  ",
				callId, ss.ConvertCallStatusToString(result.Event), playCount)
			switch result.Event {
			case ss.CALL_EVENT_ANSWER:

				if args.GetKey {
					arg := ss.DTMF_ARGS{
						KeyStop:    false,
						EndKey:     "*#",
						MediaFile:  args.PlayFile,
						MaxKey:     1,
						TimeOut:    30,
						KeyTimeOut: 15,
					}

					result.Ssion.PlayAndGetKey(arg)
				} else {

					result.Ssion.PlayVoiceToUser(args.PlayFile)

				}
			case ss.CALL_EVENT_FAIL:
				//发起外呼失败
				//sendErrResponseGet(uri, args.CallId, errSystem)
				break Loop

			case ss.CALL_EVENT_PLAY_OVER:
				playCount--

				logs.Debug("[%v]receive playover，playtimes:%d  ", callId, playCount)

				if playCount > 0 {
					if args.GetKey {
						arg := ss.DTMF_ARGS{
							KeyStop:    false,
							EndKey:     "*#",
							MediaFile:  args.PlayFile,
							MaxKey:     1,
							TimeOut:    30,
							KeyTimeOut: 15,
						}

						result.Ssion.PlayAndGetKey(arg)
					} else {

						result.Ssion.PlayVoiceToUser(args.PlayFile)
					}
				} else if playCount <= 0 {

					result.Ssion.HangUp(common.ErrPlayOver)
				}

			case ss.CALL_EVENT_HANGUP:

				hangUp := result.Data.(*ss.HangInfo)
				logs.Debug("[%v]hangup dir:%v,line:%v，duration:%v seconds",
					callId, hangUp.Dir, result.Dir, hangUp.Duration)

				if rs.Code == "" {
					if hangUp.Duration > 0 &&
						(hangUp.Dir == ss.HANG_UP_SYSTEM || len(hangUp.SipCode) == 0) {

						rs = errPlayOver
					} else {
						//播放中挂机
						switch hangUp.Dir {
						case ss.HANG_UP_LINEERR:
							rs = errCalleeLineErr
						case ss.HANG_UP_USER:
							rs = errCalleeHangup
						case ss.HANG_UP_SYSTEM:
							rs = errCalleeHangup
						default:
							//未接听
							rs = errCalleeUnAnswer
						}

						if hangUp.Duration > 0 {
							rs.Answer = true
						}
					}
				}
				result.Ssion.SendBill(args.CallBack, rs)

				break Loop
			case ss.CALL_EVENT_DTMF:

				rs = succDtmfHangup
				dtmfEv := result.Data.(ss.DtmfEvent)
				logs.Debug("[%v] receive dtmf:%v,end TimeOut:%v", result.CallId, dtmfEv.Dtmf, dtmfEv.TimeOut)

			default:
				logs.Error("[%v]wrong event:%v,drop", result.CallId, ss.ConvertCallStatusToString(result.Event))
			}
		}

		logs.Debug("[%v] call notify finished", callId)
		ss.DesdroyTheCall(callId)

	}()
	return callId, nil
}
